home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Textfiles / zines / Phrack / Phrack Issue 53.sit / 53 / P53-11 < prev    next >
Text File  |  1998-07-08  |  30KB  |  1,077 lines

  1. ---[  Phrack Magazine   Volume 8, Issue 53 July 8, 1998, article 11 of 15
  2.  
  3.  
  4. -------------------------[  Watcher
  5.  
  6.  
  7. --------[  hyperion <hyperion@hacklab.com>
  8.  
  9.  
  10. ----[  INTRODUCTION
  11.  
  12. Do you know if your system has been hacked?  If you found those funny user
  13. accounts or that Trojaned program, its too late.  You're owned.  Chances are
  14. that your systems were scanned for holes before your systems were cracked.
  15. If you had just seen them coming you wouldn't be reloading that OS right now.
  16. Programs like TCP Wrappers do some good, but they don't see the stealth scans
  17. or DOS attacks.  You could by a nice commercial network intrusion detector,
  18. but your wallet screams in agony.  What you need is a low cost (as in free)
  19. fast, somewhat paranoid network monitor that watches all packets and uses
  20. few resources.  Watcher provides this.
  21.  
  22.  
  23. ----[  IMPLEMENTATION
  24.  
  25. Watcher examines all packets on the network interface and assumes they all are
  26. potentially hostile.  Watcher examines every packet within a 10 second window,
  27. and, at the end of each window it will record any malicious activity it sees
  28. using syslog.  Watcher currently detects the following attacks:
  29.  
  30.     - All TCP scans
  31.     - All UDP scans
  32.     - Synflood attacks
  33.     - Teardrop attacks
  34.     - Land attacks
  35.     - Smurf attacks
  36.     - Ping of death attacks
  37.  
  38. All parameters and thresholds are configurable through command line options. 
  39. You can also configure watcher to just look for scans or just look for DOS
  40. attacks.  Watcher assumes any TCP packet other than a RST (which elicits no
  41. response) may be used to scan for services.  If packets of any type are
  42. received by more than 7 different ports within the window, an event is
  43. logged.  The same criteria are used for UDP scans.  If watcher sees more than
  44. 8 SYN packets to the same port with no ACK's or FIN's associated with the
  45. SYN's, a synflood event is logged.  If a fragmented UDP packet with an IP id
  46. of 242 is seen, it is assumed to be a teardrop attack since the published code
  47. uses an id of 242.  This is somewhat lame since anyone could change the
  48. attacking code to use other id's.  The code should track all fragmented IP's
  49. and check for overlapping offsets.  I may do this in a future version.  Any
  50. TCP SYN packets with source and destination address and ports the same is a
  51. identified as a land attack.  If more than 5 ICMP ECHO REPLIES are seen within
  52. the window, Watcher assumes it may be a Smurf attack.  Note that this is not a
  53. certainty, since someone your watching may just be pinging the hell out of
  54. someone.  Watcher also assumes that any fragmented ICMP packet is bad, bad,
  55. bad.  This catches attacks such as the ping of death.
  56.  
  57. Watcher has three modes of monitoring.  In the default mode, it just watches
  58. for attacks against its own host.  The second monitoring mode is to watch all
  59. hosts on it's class C subnet.  In the third mode, it watches all hosts whose
  60. packets it sees.  Watching multiple hosts is useful if you put Watcher on your
  61. border to external networks, or to have hosts watch out for each other in case
  62. one gets cracked before you can react.  Even if log files are destroyed, the
  63. other host has a record.
  64.  
  65. It must be noted that since Watcher treats every packet as potentially hostile,
  66. it sometimes can report false positives.  There are some checks in the code
  67. to minimize this by increasing its tolerance for certain activity.
  68. Unfortunately this also increases the rate at which scans can be done before
  69. Watcher notices.  The usual false positives are TCP scans and synfloods,
  70. mostly resulting from WWW activity.  Some web pages have many URL's to GIF
  71. files and other pretty stuff.  Each of these may cause the client to open a
  72. separate TCP connection to download.  Watcher sees these and treats them as
  73. a TCP scan of the client.  To minimize this, watcher will only log TCP scans
  74. if more than 40 are received in the window AND the source port of the scan
  75. was 80.  This of course can be configured higher or lower as desired.  As for
  76. synfloods we will use the same WWW example above.  If the client opens a lot
  77. of connections to the server right before the 10 second window expires and
  78. Watcher does not see the ACK's or FIN's for those SYN packets, Watcher will
  79. think the client is synflooding port 80 on the server.  This only happens
  80. if watcher is watching the server, or if you are watching everyone.  You
  81. may also get occasional false UDP scans if the system being watched makes
  82. lots of DNS queries within the window.
  83.  
  84. The output for Watcher is pretty simple.  Every 10 seconds, any detected
  85. attacks are logged to syslog.  The source and target IP's are logged along
  86. with the type of attack.  Where appropriate, other information such as the
  87. number of packets, or the port involved are logged.  If the attack is normally
  88. associated with false IP addresses, the MAC address is also logged.  If the
  89. attack is external, the MAC will be for the local router that handled the
  90. packet.  If it was from your LAN, you'll have the source machine and you can
  91. thank the sender in an appropriate manner.
  92.  
  93.  
  94. ----[  PROGRAM EXECUTION
  95.  
  96. Watcher was written to run on Linux systems.  Watcher has a variety of, most
  97. of the self-explanatory.  To execute watcher, simply run it in the background,
  98. usually from the system startup script.  The options are:
  99.  
  100. Usage: watcher [options] 
  101.   -d device       Use 'device' as the network interface device
  102.                   The first non-loopback interface is the default
  103.   -f flood        Assume a synflood attack occurred if more than
  104.                   'flood' uncompleted connections are received
  105.   -h              A little help here
  106.   -i icmplimit    Assume we may be part of a smurf attack if more
  107.                   than icmplimit ICMP ECHO REPLIES are seen
  108.   -m level        Monitor more than just our own host.
  109.                   A level of 'subnet' watches all addresses in our
  110.                   subnet and 'all' watches all addresses
  111.   -p portlimit    Logs a portscan alert if packets are received for
  112.                   more than portlimit ports in the timeout period.
  113.   -r reporttype   If reporttype is dos, only Denial Of Service
  114.                   attacks are reported.  If reporttype is scan
  115.                   then only scanners are reported.  Everything is
  116.                   reported by default.
  117.   -t timeout      Count packets and print potential attacks every
  118.                   timeout seconds
  119.   -w webcount     Assume we are being portscanned if more than
  120.                   webcount packets are received from port 80
  121.  
  122. Hopefully, watcher will keep your systems a little better protected.  But
  123. remember that good security is multiple layers, and no single defense tool will
  124. save you by itself.  If you forget this, you'll be reloading that OS one day.
  125.  
  126.  
  127. ----[  THE CODE
  128.  
  129. <++> EX/Watcher.c
  130. /*********************************************************************
  131. Program: watcher
  132.  
  133. A network level monitoring tool to detect incoming packets indicative of
  134. potential attacks.
  135.  
  136. This software detects low level packet scanners and several DOS attacks.
  137. Its primary use is to detect low level packet scans, since these are usually
  138. done first to identify active systems and services to mount further attacks.
  139.  
  140. The package assumes every incoming packet is potentially hostile.  Some checks
  141. are done to minimize false positives, but on occasion a site may be falsely
  142. identified as having performed a packet scan or SYNFLOOD attack.  This usually
  143. occurs if a large number of connections are done in a brief time right before
  144. the reporting timeout period (i.e. when browsing a WWW site with lots of
  145. little GIF's, each requiring a connection to download).  You can also get false
  146. positives if you scan another site, since the targets responses will be viewed
  147. as a potential scan of your system.
  148.  
  149. By default, alerts are printed to SYSLOG every 10 seconds.
  150. ***********************************************************************/
  151.  
  152. #include <stdio.h>
  153. #include <sys/types.h>
  154. #include <sys/time.h>
  155. #include <sys/socket.h>
  156. #include <sys/file.h>
  157. #include <sys/time.h>
  158. #include <netinet/in.h>
  159. #include <netdb.h>
  160. #include <string.h>
  161. #include <errno.h>
  162. #include <ctype.h>
  163. #include <malloc.h>
  164. #include <netinet/tcp.h>
  165. #include <netinet/in_systm.h>
  166. #include <net/if_arp.h>
  167. #include <net/if.h>
  168. #include <netinet/udp.h>
  169. #include <netinet/ip.h>
  170. #include <netinet/ip_icmp.h>
  171. #include <linux/if_ether.h>
  172. #include <syslog.h>
  173.  
  174. #define PKTLEN 96    /* Should be enough for what we want */
  175. #ifndef IP_MF
  176. #define IP_MF    0x2000
  177. #endif
  178.  
  179. /***** WATCH LEVELS ******/
  180.  
  181. #define MYSELFONLY    1
  182. #define MYSUBNET    2
  183. #define HUMANITARIAN    3
  184.  
  185. /***** REPORT LEVELS *****/
  186.  
  187. #define REPORTALL    1
  188. #define REPORTDOS    2
  189. #define REPORTSCAN    3
  190.  
  191. struct floodinfo {
  192.     u_short sport;
  193.     struct floodinfo *next;
  194. };
  195.  
  196. struct addrlist {
  197.     u_long saddr;
  198.     int cnt;
  199.     int wwwcnt;
  200.     struct addrlist *next;
  201. };
  202.  
  203. struct atk {
  204.     u_long saddr;
  205.     u_char eaddr[ETH_ALEN];
  206.     time_t atktime;
  207. };
  208.  
  209. struct pktin {
  210.     u_long saddr;
  211.     u_short sport;
  212.     u_short dport;
  213.     time_t timein;
  214.     u_char eaddr[ETH_ALEN];
  215.     struct floodinfo *fi;
  216.     struct pktin *next;
  217. };
  218.  
  219. struct scaninfo {
  220.     u_long addr;
  221.     struct atk teardrop;
  222.     struct atk land;
  223.     struct atk icmpfrag;
  224.     struct pktin *tcpin;
  225.     struct pktin *udpin;
  226.     struct scaninfo *next;
  227.     u_long icmpcnt;
  228. } ;
  229.  
  230. struct scaninfo *Gsilist = NULL, *Gsi;
  231.  
  232. u_long Gmaddr;
  233. time_t Gtimer = 10, Gtimein;
  234. int Gportlimit = 7;
  235. int Gsynflood = 8;
  236. int Gwebcount = 40;
  237. int Gicmplimit = 5;
  238. int Gwatchlevel = MYSELFONLY;
  239. int Greportlevel = REPORTALL;
  240. char *Gprogramname, *Gdevice = "eth0";
  241.  
  242. /******** IP packet info ********/
  243.  
  244. u_long Gsaddr, Gdaddr;
  245. int Giplen, Gisfrag, Gid;
  246.  
  247. /****** Externals *************/
  248.  
  249. extern int errno;
  250. extern char *optarg;
  251. extern int optind, opterr;
  252.  
  253. void do_tcp(), do_udp(), do_icmp(), print_info(), process_packet();
  254. void addtcp(), addudp(), clear_pktin(), buildnet();
  255. void doargs(), usage(), addfloodinfo(), rmfloodinfo();
  256. struct scaninfo *doicare(), *addtarget();
  257. char *anetaddr(), *ether_ntoa();
  258. u_char *readdevice();
  259.  
  260. main(argc, argv)
  261. int argc;
  262. char *argv[];
  263. {
  264.     int pktlen = 0, i, netfd;
  265.     u_char *pkt;
  266.     char hostname[32];
  267.     struct hostent *hp;
  268.     time_t t;
  269.  
  270.     doargs(argc, argv);
  271.     openlog("WATCHER", 0, LOG_DAEMON);
  272.     if(gethostname(hostname, sizeof(hostname)) < 0)
  273.     {
  274.     perror("gethostname");
  275.     exit(-1);
  276.     }
  277.     if((hp = gethostbyname(hostname)) == NULL)
  278.     {
  279.     fprintf(stderr, "Cannot find own address\n");
  280.     exit(-1);
  281.     }
  282.     memcpy((char *)&Gmaddr, hp->h_addr, hp->h_length);
  283.     buildnet();
  284.     if((netfd = initdevice(O_RDWR, 0)) < 0)
  285.     exit(-1);
  286.  
  287.     /* Now read packets forever and process them. */
  288.  
  289.     t = time((time_t *)0);
  290.     while(pkt = readdevice(netfd, &pktlen))
  291.     {
  292.     process_packet(pkt, pktlen);
  293.     if(time((time_t *)0) - t > Gtimer)
  294.     {
  295.         /* Times up.  Print what we found and clean out old stuff. */
  296.  
  297.         for(Gsi = Gsilist, i = 0; Gsi; Gsi = Gsi->next, i++)
  298.         {
  299.                 clear_pktin(Gsi);
  300.             print_info();
  301.         Gsi->icmpcnt = 0;
  302.         }
  303.         t = time((time_t *)0);
  304.     }
  305.     }
  306. }
  307.  
  308. /**********************************************************************
  309. Function: doargs
  310.  
  311. Purpose:  sets values from environment or command line arguments.
  312. **********************************************************************/
  313. void doargs(argc, argv)
  314. int argc;
  315. char **argv;
  316. {
  317.     char c;
  318.  
  319.     Gprogramname = argv[0];
  320.     while((c = getopt(argc,argv,"d:f:hi:m:p:r:t:w:")) != EOF)
  321.     {
  322.         switch(c)
  323.         {
  324.         case 'd':
  325.         Gdevice = optarg;
  326.         break;
  327.             case 'f':
  328.                 Gsynflood = atoi(optarg);
  329.                 break;
  330.         case 'h':
  331.         usage();
  332.         exit(0);
  333.         case 'i':
  334.         Gicmplimit = atoi(optarg);
  335.         break;
  336.         case 'm':
  337.         if(strcmp(optarg, "all") == 0)
  338.             Gwatchlevel = HUMANITARIAN;
  339.         else if(strcmp(optarg, "subnet") == 0)
  340.             Gwatchlevel = MYSUBNET;
  341.         else
  342.         {
  343.             usage();
  344.             exit(-1);
  345.         }
  346.         break;
  347.         case 'p':
  348.         Gportlimit = atoi(optarg);
  349.         break;
  350.         case 'r':
  351.         if(strcmp(optarg, "dos") == 0)
  352.             Greportlevel = REPORTDOS;
  353.         else if(strcmp(optarg, "scan") == 0)
  354.             Greportlevel = REPORTSCAN;
  355.         else
  356.         {
  357.             exit(-1);
  358.         }
  359.         break;
  360.         case 't':
  361.                 Gtimer = atoi(optarg);
  362.                 break;
  363.         case 'w':
  364.         Gwebcount = atoi(optarg);
  365.         break;
  366.         default:
  367.                 usage();
  368.                 exit(-1);
  369.         }
  370.     }
  371. }
  372.  
  373. /**********************************************************************
  374. Function: usage
  375.  
  376. Purpose:  Display the usage of the program
  377. **********************************************************************/
  378. void usage()
  379. {
  380. printf("Usage: %s [options]\n", Gprogramname);
  381. printf("  -d device       Use 'device' as the network interface device\n");
  382. printf("                  The first non-loopback interface is the default\n");
  383. printf("  -f flood        Assume a synflood attack occurred if more than\n");
  384. printf("                  'flood' uncompleted connections are received\n");
  385. printf("  -h              A little help here\n");
  386. printf("  -i icmplimit    Assume we may be part of a smurf attack if more\n");
  387. printf("                  than icmplimit ICMP ECHO REPLIES are seen\n");
  388. printf("  -m level        Monitor more than just our own host.\n");
  389. printf("                  A level of 'subnet' watches all addresses in our\n");
  390. printf("                  subnet and 'all' watches all addresses\n");
  391. printf("  -p portlimit    Logs a portscan alert if packets are received for\n");
  392. printf("                  more than portlimit ports in the timeout period.\n");
  393. printf("  -r reporttype   If reporttype is dos, only Denial Of Service\n");
  394. printf("                  attacks are reported.  If reporttype is scan\n");
  395. printf("                  then only scanners are reported.  Everything is\n");
  396. printf("                  reported by default.\n");
  397. printf("  -t timeout      Count packets and print potential attacks every\n");
  398. printf("                  timeout seconds\n");
  399. printf("  -w webcount     Assume we are being portscanned if more than\n");
  400. printf("                  webcount packets are received from port 80\n");
  401. }
  402.  
  403. /**********************************************************************
  404. Function: buildnet
  405.  
  406. Purpose:  Setup for monitoring of our host or entire subnet.
  407. **********************************************************************/
  408. void buildnet()
  409. {
  410.     u_long addr;
  411.     u_char *p;
  412.     int i;
  413.  
  414.     if(Gwatchlevel == MYSELFONLY)        /* Just care about me */
  415.     {
  416.     (void) addtarget(Gmaddr);
  417.     }
  418.     else if(Gwatchlevel == MYSUBNET)        /* Friends and neighbors */
  419.     {
  420.     addr = htonl(Gmaddr);
  421.     addr = addr & 0xffffff00;
  422.     for(i = 0; i < 256; i++)
  423.         (void) addtarget(ntohl(addr + i));
  424.     }
  425. }
  426. /**********************************************************************
  427. Function: doicare
  428.  
  429. Purpose:  See if we monitor this address
  430. **********************************************************************/
  431. struct scaninfo *doicare(addr)
  432. u_long addr;
  433. {
  434.     struct scaninfo *si;
  435.     int i;
  436.  
  437.     for(si = Gsilist; si; si = si->next)
  438.     {
  439.     if(si->addr == addr)
  440.         return(si);
  441.     }
  442.     if(Gwatchlevel == HUMANITARIAN)    /* Add a new address, we always care */
  443.     {
  444.     si = addtarget(addr);
  445.     return(si);
  446.     }
  447.     return(NULL);
  448. }
  449.  
  450. /**********************************************************************
  451. Function: addtarget
  452.  
  453. Purpose:  Adds a new IP address to the list of hosts to watch.
  454. **********************************************************************/
  455. struct scaninfo *addtarget(addr)
  456. u_long addr;
  457. {
  458.     struct scaninfo *si;
  459.  
  460.     if((si = (struct scaninfo *)malloc(sizeof(struct scaninfo))) == NULL)
  461.     {
  462.     perror("malloc scaninfo");
  463.     exit(-1);
  464.     }
  465.     memset(si, 0, sizeof(struct scaninfo));
  466.     si->addr = addr;
  467.     si->next = Gsilist;
  468.     Gsilist = si;
  469.     return(si);
  470. }
  471.  
  472. /**********************************************************************
  473. Function: process_packet
  474.  
  475. Purpose:  Process raw packet and figure out what we need to to with it.
  476.  
  477. Pulls the packet apart and stores key data in global areas for reference
  478. by other functions.
  479. **********************************************************************/
  480. void process_packet(pkt, pktlen)
  481. u_char *pkt;
  482. int pktlen;
  483. {
  484.     struct ethhdr *ep;
  485.     struct iphdr *ip;
  486.     static struct align { struct iphdr ip; char buf[PKTLEN]; } a1;
  487.     u_short off;
  488.  
  489.     Gtimein = time((time_t *)0);
  490.     ep = (struct ethhdr *) pkt;
  491.     if(ntohs(ep->h_proto) != ETH_P_IP)
  492.     return;
  493.  
  494.     pkt += sizeof(struct ethhdr);
  495.     pktlen -= sizeof(struct ethhdr);
  496.     memcpy(&a1, pkt, pktlen);
  497.     ip = &a1.ip;
  498.     Gsaddr = ip->saddr;
  499.     Gdaddr = ip->daddr;
  500.  
  501.     if((Gsi = doicare(Gdaddr)) == NULL)
  502.     return;
  503.  
  504.     off = ntohs(ip->frag_off);
  505.     Gisfrag = (off & IP_MF);    /* Set if packet is fragmented */
  506.     Giplen = ntohs(ip->tot_len);
  507.     Gid = ntohs(ip->id);
  508.     pkt = (u_char *)ip + (ip->ihl << 2);
  509.     Giplen -= (ip->ihl << 2);
  510.     switch(ip->protocol)
  511.     {
  512.     case IPPROTO_TCP:
  513.         do_tcp(ep, pkt);
  514.         break;
  515.     case IPPROTO_UDP:
  516.         do_udp(ep, pkt);
  517.         break;
  518.     case IPPROTO_ICMP:
  519.         do_icmp(ep, pkt);
  520.         break;
  521.     default:
  522.         break;
  523.     }
  524. }
  525.  
  526. /**********************************************************************
  527. Function: do_tcp
  528.  
  529. Purpose:  Process this TCP packet if it is important.
  530. **********************************************************************/
  531. void do_tcp(ep, pkt)
  532. struct ethhdr *ep;
  533. u_char *pkt;
  534. {
  535.     struct tcphdr *thdr;
  536.     u_short sport, dport;
  537.  
  538.     thdr = (struct tcphdr *) pkt;
  539.     if(thdr->th_flags & TH_RST) /* RST generates no response */
  540.     return;            /* Therefore can't be used to scan. */
  541.     sport = ntohs(thdr->th_sport);
  542.     dport = ntohs(thdr->th_dport);
  543.  
  544.     if(thdr->th_flags & TH_SYN)
  545.     {
  546.     if(Gsaddr == Gdaddr && sport == dport)
  547.     {
  548.         Gsi->land.atktime = Gtimein;
  549.         Gsi->land.saddr = Gsaddr;
  550.         memcpy(Gsi->land.eaddr, ep->h_source, ETH_ALEN);
  551.     }
  552.     }
  553.     addtcp(sport, dport, thdr->th_flags, ep->h_source);
  554. }
  555.  
  556. /**********************************************************************
  557. Function: addtcp
  558.  
  559. Purpose:  Add this TCP packet to our list.
  560. **********************************************************************/
  561. void addtcp(sport, dport, flags, eaddr)
  562. u_short sport;
  563. u_short dport;
  564. u_char flags;
  565. u_char *eaddr;
  566. {
  567.     struct pktin *pi, *last, *tpi;
  568.  
  569.     /* See if this packet relates to other packets already received. */
  570.  
  571.     for(pi = Gsi->tcpin; pi; pi = pi->next)
  572.     {
  573.     if(pi->saddr == Gsaddr && pi->dport == dport)
  574.     {
  575.         if(flags == TH_SYN)
  576.         addfloodinfo(pi, sport);
  577.         else if((flags & TH_FIN) || (flags & TH_ACK))
  578.         rmfloodinfo(pi, sport);
  579.         return;
  580.     }
  581.     last = pi;
  582.     }
  583.     /* Must be new entry */
  584.  
  585.     if((tpi = (struct pktin *)malloc(sizeof(struct pktin))) == NULL)
  586.     {
  587.     perror("Malloc");
  588.     exit(-1);
  589.     }
  590.     memset(tpi, 0, sizeof(struct pktin));
  591.     memcpy(tpi->eaddr, eaddr, ETH_ALEN);
  592.     tpi->saddr = Gsaddr;
  593.     tpi->sport = sport;
  594.     tpi->dport = dport;
  595.     tpi->timein = Gtimein;
  596.     if(flags == TH_SYN)
  597.     addfloodinfo(tpi, sport);
  598.     if(Gsi->tcpin)
  599.     last->next = tpi;
  600.     else
  601.     Gsi->tcpin = tpi;
  602. }
  603.  
  604. /**********************************************************************
  605. Function: addfloodinfo
  606.  
  607. Purpose:  Add floodinfo information
  608. **********************************************************************/
  609. void addfloodinfo(pi, sport)
  610. struct pktin *pi;
  611. u_short sport;
  612. {
  613.     struct floodinfo *fi;
  614.  
  615.     fi = (struct floodinfo *)malloc(sizeof(struct floodinfo));
  616.     if(fi == NULL)
  617.     {
  618.         perror("Malloc of floodinfo");
  619.         exit(-1);
  620.     }
  621.     memset(fi, 0, sizeof(struct floodinfo));
  622.     fi->sport = sport;
  623.     fi->next = pi->fi;
  624.     pi->fi = fi;
  625. }
  626.  
  627. /**********************************************************************
  628. Function: rmfloodinfo
  629.  
  630. Purpose:  Removes floodinfo information
  631. **********************************************************************/
  632. void rmfloodinfo(pi, sport)
  633. struct pktin *pi;
  634. u_short sport;
  635. {
  636.     struct floodinfo *fi, *prev = NULL;
  637.  
  638.     for(fi = pi->fi; fi; fi = fi->next)
  639.     {
  640.     if(fi->sport == sport)
  641.         break;
  642.     prev = fi;
  643.     }
  644.     if(fi == NULL)
  645.     return;
  646.     if(prev == NULL)    /* First element */
  647.     pi->fi = fi->next;
  648.     else
  649.     prev->next = fi->next;
  650.     free(fi);
  651. }
  652.  
  653. /**********************************************************************
  654. Function: do_udp
  655.  
  656. Purpose:  Process this udp packet.
  657.  
  658. Currently teardrop and all its derivitives put 242 in the IP id field.
  659. This could obviously be changed.  The truly paranoid might want to flag all
  660. fragmented UDP packets.  The truly adventurous might enhance the code to
  661. track fragments and check them for overlaping boundaries.
  662. **********************************************************************/
  663. void do_udp(ep, pkt)
  664. struct ethhdr *ep;
  665. u_char *pkt;
  666. {
  667.     struct udphdr *uhdr;
  668.     u_short sport, dport;
  669.  
  670.     uhdr = (struct udphdr *) pkt;
  671.     if(Gid == 242 && Gisfrag)    /* probable teardrop */
  672.     {
  673.     Gsi->teardrop.saddr = Gsaddr;
  674.     memcpy(Gsi->teardrop.eaddr, ep->h_source, ETH_ALEN);
  675.     Gsi->teardrop.atktime = Gtimein;
  676.     }
  677.     sport = ntohs(uhdr->source);
  678.     dport = ntohs(uhdr->dest);
  679.     addudp(sport, dport, ep->h_source);
  680. }
  681.  
  682. /**********************************************************************
  683. Function: addudp
  684.  
  685. Purpose:  Add this udp packet to our list.
  686. **********************************************************************/
  687. void addudp(sport, dport, eaddr)
  688. u_short sport;
  689. u_short dport;
  690. u_char *eaddr;
  691. {
  692.     struct pktin *pi, *last, *tpi;
  693.  
  694.     for(pi = Gsi->udpin; pi; pi = pi->next)
  695.     {
  696.     if(pi->saddr == Gsaddr && pi->dport == dport)
  697.     {
  698.         pi->timein = Gtimein;
  699.         return;
  700.     }
  701.     last = pi;
  702.     }
  703.     /* Must be new entry */
  704.  
  705.     if((tpi = (struct pktin *)malloc(sizeof(struct pktin))) == NULL)
  706.     {
  707.     perror("Malloc");
  708.     exit(-1);
  709.     }
  710.     memset(tpi, 0, sizeof(struct pktin));
  711.     memcpy(tpi->eaddr, eaddr, ETH_ALEN);
  712.     tpi->saddr = Gsaddr;
  713.     tpi->sport = sport;
  714.     tpi->dport = dport;
  715.     tpi->timein = Gtimein;
  716.     if(Gsi->udpin)
  717.     last->next = tpi;
  718.     else
  719.     Gsi->udpin = tpi;
  720. }
  721.  
  722. /**********************************************************************
  723. Function: do_icmp
  724.  
  725. Purpose:  Process an ICMP packet.
  726.  
  727. We assume there is no valid reason to receive a fragmented ICMP packet.
  728. **********************************************************************/
  729. void do_icmp(ep, pkt)
  730. struct ethhdr *ep;
  731. u_char *pkt;
  732. {
  733.     struct icmphdr *icmp;
  734.  
  735.     icmp = (struct icmphdr *) pkt;
  736.     if(Gisfrag)    /* probable ICMP attack (i.e. Ping of Death) */
  737.     {
  738.     Gsi->icmpfrag.saddr = Gsaddr;
  739.     memcpy(Gsi->icmpfrag.eaddr, ep->h_source, ETH_ALEN);
  740.     Gsi->icmpfrag.atktime = Gtimein;
  741.     }
  742.     if(icmp->type == ICMP_ECHOREPLY)
  743.     Gsi->icmpcnt++;
  744.     return;
  745. }
  746.  
  747. /**********************************************************************
  748. Function: clear_pkt
  749.  
  750. Purpose:  Delete and free space for any old packets.
  751. **********************************************************************/
  752. void clear_pktin(si)
  753. struct scaninfo *si;
  754. {
  755.     struct pktin *pi;
  756.     struct floodinfo *fi, *tfi;
  757.     time_t t, t2;
  758.  
  759.     t = time((time_t *)0);
  760.     while(si->tcpin)
  761.     {
  762.     t2 = t - si->tcpin->timein;
  763.     if(t2 > Gtimer)
  764.     {
  765.         pi = si->tcpin;
  766.         fi = pi->fi;
  767.         while(fi)
  768.         {
  769.         tfi = fi;
  770.         fi = fi->next;
  771.         free(tfi);
  772.         }
  773.         si->tcpin = pi->next;
  774.         free(pi);
  775.     }
  776.     else
  777.         break;
  778.     }
  779.     while(si->udpin)
  780.     {
  781.     t2 = t - si->udpin->timein;
  782.     if(t2 > Gtimer)
  783.     {
  784.         pi = si->udpin;
  785.         si->udpin = pi->next;
  786.         free(pi);
  787.     }
  788.     else
  789.         break;
  790.     }
  791. }
  792.  
  793. /**********************************************************************
  794. Function: print_info
  795.  
  796. Purpose:  Print out any alerts.
  797. **********************************************************************/
  798. void print_info()
  799. {
  800.     struct pktin *pi;
  801.     struct addrlist *tcplist = NULL, *udplist = NULL, *al;
  802.     struct floodinfo *fi;
  803.     char buf[1024], *eaddr, abuf[32];
  804.     int i;
  805.  
  806.     strcpy(abuf, anetaddr(Gsi->addr));
  807.     if(Greportlevel == REPORTALL || Greportlevel == REPORTDOS)
  808.     {
  809.         if(Gsi->teardrop.atktime)
  810.         {
  811.         eaddr = ether_ntoa(Gsi->teardrop.eaddr);
  812.         sprintf(buf, "Possible teardrop attack from %s (%s) against %s",
  813.             anetaddr(Gsi->teardrop), eaddr, abuf);
  814.         syslog(LOG_ALERT, buf);
  815.         memset(&Gsi->teardrop, 0, sizeof(struct atk));
  816.         }
  817.         if(Gsi->land.atktime)
  818.         {
  819.         eaddr = ether_ntoa(Gsi->land.eaddr);
  820.         sprintf(buf, "Possible land attack from (%s) against %s",
  821.             eaddr, abuf);
  822.         syslog(LOG_ALERT, buf);
  823.         memset(&Gsi->land, 0, sizeof(struct atk));
  824.         }
  825.         if(Gsi->icmpfrag.atktime)
  826.         {
  827.         eaddr = ether_ntoa(Gsi->icmpfrag.eaddr);
  828.         sprintf(buf, "ICMP fragment detected from %s (%s) against %s",
  829.             anetaddr(Gsi->icmpfrag), eaddr, abuf);
  830.         syslog(LOG_ALERT, buf);
  831.         memset(&Gsi->icmpfrag, 0, sizeof(struct atk));
  832.         }
  833.         if(Gsi->icmpcnt > Gicmplimit)
  834.         {
  835.         sprintf(buf, "ICMP ECHO threshold exceeded, smurfs up.  I saw %d packets\n", Gsi->icmpcnt);
  836.         syslog(LOG_ALERT, buf);
  837.         Gsi->icmpcnt = 0;
  838.         }
  839.     
  840.     }
  841.     for(pi = Gsi->tcpin; pi; pi = pi->next)
  842.     {
  843.     i = 0;
  844.     for(fi = pi->fi; fi; fi = fi->next)
  845.         i++;
  846.         
  847.     if(Greportlevel == REPORTALL || Greportlevel == REPORTDOS)
  848.     {
  849.         if(i > Gsynflood)
  850.         {
  851.             eaddr = ether_ntoa(pi->eaddr);
  852.             sprintf(buf, "Possible SYNFLOOD from %s (%s), against %s.  I saw %d packets\n",
  853.             anetaddr(pi->saddr), eaddr, abuf, i);
  854.             syslog(LOG_ALERT, buf);
  855.         }
  856.     }
  857.     for(al = tcplist; al; al = al->next)
  858.     {
  859.         if(pi->saddr == al->saddr)
  860.         {
  861.         al->cnt++;
  862.         if(pi->sport == 80)
  863.             al->wwwcnt++;
  864.         break;
  865.         }
  866.     }
  867.     if(al == NULL)    /* new address */
  868.     {
  869.         al = (struct addrlist *)malloc(sizeof(struct addrlist));
  870.         if(al == NULL)
  871.         {
  872.         perror("Malloc address list");
  873.         exit(-1);
  874.         }
  875.         memset(al, 0, sizeof(struct addrlist));
  876.         al->saddr = pi->saddr;
  877.         al->cnt = 1;
  878.         if(pi->sport == 80)
  879.         al->wwwcnt = 1;
  880.         al->next = tcplist;
  881.         tcplist = al;
  882.         }
  883.     }
  884.     if(Greportlevel == REPORTALL || Greportlevel == REPORTSCAN)
  885.     {
  886.         for(al = tcplist; al; al = al->next)
  887.         {
  888.         if((al->cnt - al->wwwcnt) > Gportlimit || al->wwwcnt > Gwebcount)
  889.         {
  890.             sprintf(buf, "Possible TCP port scan from %s (%d ports) against %s\n",
  891.             anetaddr(al->saddr), al->cnt, abuf);
  892.             syslog(LOG_ALERT, buf);
  893.         }
  894.         }
  895.  
  896.         for(pi = Gsi->udpin; pi; pi = pi->next)
  897.         {
  898.         for(al = udplist; al; al = al->next)
  899.         {
  900.             if(pi->saddr == al->saddr)
  901.             {
  902.             al->cnt++;
  903.             break;
  904.             }
  905.         }
  906.         if(al == NULL)    /* new address */
  907.         {
  908.             al = (struct addrlist *)malloc(sizeof(struct addrlist));
  909.             if(al == NULL)
  910.             {
  911.             perror("Malloc address list");
  912.             exit(-1);
  913.             }
  914.             memset(al, 0, sizeof(struct addrlist));
  915.             al->saddr = pi->saddr;
  916.             al->cnt = 1;
  917.             al->next = udplist;
  918.             udplist = al;
  919.         }
  920.         }
  921.         for(al = udplist; al; al = al->next)
  922.         {
  923.         if(al->cnt > Gportlimit)
  924.         {
  925.             sprintf(buf, "Possible UDP port scan from %s (%d ports) against %s\n",
  926.             anetaddr(al->saddr), al->cnt, abuf);
  927.             syslog(LOG_ALERT, buf);
  928.         }
  929.         }
  930.     }
  931.  
  932.     while(tcplist)
  933.     {
  934.     al = tcplist->next;
  935.     free(tcplist);
  936.     tcplist = al;
  937.     }
  938.     while(udplist)
  939.     {
  940.     al = udplist->next;
  941.     free(udplist);
  942.     udplist = al;
  943.     }
  944. }
  945.  
  946. /************************************************************************
  947. Function:  anetaddr
  948.  
  949. Description:
  950.  
  951. Another version of the intoa function.
  952. ************************************************************************/
  953.  
  954. char *anetaddr(addr)
  955. u_long addr;
  956. {
  957.     u_long naddr;
  958.     static char buf[16];
  959.     u_char b[4];
  960.     int i;
  961.  
  962.     naddr = ntohl(addr);
  963.     for(i = 3; i >= 0; i--)
  964.     {
  965.         b[i] = (u_char) (naddr & 0xff);
  966.         naddr >>= 8;
  967.     }
  968.     sprintf(buf, "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
  969.     return(buf);
  970. }
  971.  
  972. /************************************************************************
  973. Function:  initdevice
  974.  
  975. Description: Set up the network device so we can read it.
  976.  
  977. **************************************************************************/
  978. initdevice(fd_flags, dflags)
  979. int fd_flags;
  980. u_long dflags;
  981. {
  982.     struct ifreq ifr;
  983.     int fd, flags = 0;
  984.  
  985.     if((fd = socket(PF_INET, SOCK_PACKET, htons(0x0003))) < 0)
  986.     {
  987.     perror("Cannot open device socket");
  988.     exit(-1);
  989.     }
  990.  
  991.     /* Get the existing interface flags */
  992.  
  993.     strcpy(ifr.ifr_name, Gdevice);
  994.     if(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
  995.     {
  996.     perror("Cannot get interface flags");
  997.     exit(-1);
  998.     }
  999.  
  1000.     ifr.ifr_flags |= IFF_PROMISC;
  1001.     if(ioctl(fd, SIOCSIFFLAGS,  &ifr) < 0)
  1002.     {
  1003.     perror("Cannot set interface flags");
  1004.     exit(-1);
  1005.     }
  1006.     
  1007.     return(fd);
  1008. }
  1009.  
  1010. /************************************************************************
  1011. Function:  readdevice
  1012.  
  1013. Description: Read a packet from the device.
  1014.  
  1015. **************************************************************************/
  1016. u_char *readdevice(fd, pktlen)
  1017. int fd;
  1018. int *pktlen;
  1019. {
  1020.     int cc = 0, from_len, readmore = 1;
  1021.     struct sockaddr from;
  1022.     static u_char pktbuffer[PKTLEN];
  1023.     u_char *cp;
  1024.  
  1025.     while(readmore)
  1026.     {
  1027.     from_len = sizeof(from);
  1028.     if((cc = recvfrom(fd, pktbuffer, PKTLEN, 0, &from, &from_len)) < 0)
  1029.     {
  1030.         if(errno != EWOULDBLOCK)
  1031.         return(NULL);
  1032.     }
  1033.     if(strcmp(Gdevice, from.sa_data) == 0)
  1034.         readmore = 0;
  1035.     }
  1036.     *pktlen = cc;
  1037.     return(pktbuffer);
  1038. }
  1039.  
  1040. /*************************************************************************
  1041. Function: ether_ntoa 
  1042.  
  1043. Description:
  1044.  
  1045. Translates a MAC address into ascii.  This function emulates
  1046. the ether_ntoa function that exists on Sun and Solaris, but not on Linux.
  1047. It could probably (almost certainly) be more efficent, but it will do.
  1048. *************************************************************************/
  1049. char *ether_ntoa(etheraddr)
  1050. u_char etheraddr[ETH_ALEN];
  1051. {
  1052.     int i, j;
  1053.     static char eout[32];
  1054.     char tbuf[10];
  1055.  
  1056.     for(i = 0, j = 0; i < 5; i++)
  1057.     {
  1058.     eout[j++] = etheraddr[i] >> 4;
  1059.     eout[j++] = etheraddr[i] & 0xF;
  1060.     eout[j++] = ':';
  1061.     }
  1062.     eout[j++] = etheraddr[i] >> 4;
  1063.     eout[j++] = etheraddr[i] & 0xF;
  1064.     eout[j++] = '\0';
  1065.     for(i = 0; i < 17; i++)
  1066.     {
  1067.     if(eout[i] < 10)
  1068.         eout[i] += 0x30;
  1069.     else if(eout[i] < 16)
  1070.         eout[i] += 0x57;
  1071.     }
  1072.     return(eout);
  1073. }
  1074. <-->
  1075. ----[  EOF
  1076.  
  1077.